﻿package plugins.mstandio.HotSpotPlacer{
	
	import adobe.utils.ProductManager;
	import flash.display.Sprite;
	import flash.text.TextField;
	import flash.text.TextFormat;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.display.Bitmap;
	import flash.display.Loader;
	import gs.TweenLite;
	import flash.net.URLRequest;
	import flash.events.IOErrorEvent;
	
	import flash.system.ApplicationDomain;	
	import flash.utils.Dictionary;
	import flash.utils.getDefinitionByName;				
	import zephyr.BroadcastEvent;
	
	import plugins.mstandio.HotSpotPlacer.configure.*;
	import plugins.mstandio.HotSpotPlacer.hotspot.Hotspotdata;
	import plugins.mstandio.utils.combobox.ComboBox;
	import plugins.mstandio.utils.combobox.ComboBoxEvent;	
	import plugins.mstandio.utils.imageloader.ImageLoader;
	
	/**
	 * Simple tool, helpfull for placing SpaceHotspots
	 * @author mstandio
	 */
	public class HotSpotPlacer extends Sprite{
		
		private var txtPan:TextField;
		private var txtTilt:TextField;
		private var txtZoom:TextField;						
		private var txtFormat:TextFormat;							
		private var box:Sprite;		
		private var cross:Sprite;		
		private var toggleCrossButton:Sprite;
		private var toggleXmlButton:Sprite;
		private var showChangesButton:Sprite;
		[Embed(source="images/cross.png")]
			public var Bitmap_crossIcon:Class;
		[Embed(source="images/cross_v.png")]
			public var Bitmap_crossvIcon:Class;	
		[Embed(source="images/cross_h.png")]
			public var Bitmap_crosshIcon:Class;	
		[Embed(source="images/xml_v.png")]
			public var Bitmap_xmlvIcon:Class;	
		[Embed(source="images/xml_h.png")]
			public var Bitmap_xmlhIcon:Class;	
		[Embed(source="images/play.png")]
			public var Bitmap_playIcon:Class;						
		
		private var hotspotBar:Sprite;
		private var hotspotAddButton:Sprite;
		private var hotspotRemoveButton:Sprite;
		private var hotspotEditButton:Sprite;
		[Embed(source="images/add_enabled.png")]
			public var Bitmap_addenabled:Class;
		[Embed(source="images/add_disabled.png")]
			public var Bitmap_adddisabled:Class;	
		[Embed(source="images/remove_enabled.png")]
			public var Bitmap_removeenabled:Class;	
		[Embed(source="images/remove_disabled.png")]
			public var Bitmap_removedisabled:Class;		
		[Embed(source="images/edit_enabled.png")]
			public var Bitmap_editenabled:Class;
		[Embed(source="images/edit_disabled.png")]
			public var Bitmap_editdisabled:Class;	
			
		private var configurationWindow:ConfigurationWindow;
			
		private var comboBox:ComboBox;
		private var files:Array;			
			
		private var imagefield:Sprite;
		private var hotSpotImage:Loader; // External image
			
		private var statistics:Boolean;		
		private var pan:Number;
		private var tilt:Number;
		private var zoom:Number;		
		private var cameraFocus:Number;				
				
		private var SpaceHotspots:Array;
		
		private var currentSpace:String = "";
		private var BroadcastEvent:Class;
		private var ModuleLoader:Class;               
        private var moduleLoader:Object;
		private var PanoSalado:Class;		
		private var layerByName:Dictionary;	
		private var panoSalado:Object;		
		
		private var txtLog:TextField; 
		
		public function HotSpotPlacer()	{
			if (stage) stageReady();
			else addEventListener(Event.ADDED_TO_STAGE, stageReady, false, 0, true);      
		}
		
		private function stageReady(e:Event = null):void {            
			removeEventListener(Event.ADDED_TO_STAGE, stageReady);								
			
			BroadcastEvent = ApplicationDomain.currentDomain.getDefinition("zephyr.BroadcastEvent") as Class;						
			ModuleLoader = ApplicationDomain.currentDomain.getDefinition("ModuleLoader") as Class;                       			
            moduleLoader = ModuleLoader(this.root.parent);									
			
			this.stage.addEventListener(Event.RESIZE, this.handleStageResize); 									
			
			moduleLoader.addEventListener(BroadcastEvent.ALL_LAYERS_LOADED, layersReady, false, 0, true);			
			moduleLoader.addEventListener(BroadcastEvent.SPACE_LOADED, spaceLoaded, false, 0, true);
			moduleLoader.addEventListener(BroadcastEvent.CAMERA_INIT, camInit, false, 0, true);
			moduleLoader.addEventListener(BroadcastEvent.CAMERA_SPIN, camSpin, false, 0, true);	
			moduleLoader.addEventListener(BroadcastEvent.CAMERA_ZOOM, camZoom, false, 0, true);															
		}
		
		private function layersReady(e:zephyr.BroadcastEvent):void {	
			PanoSalado = ApplicationDomain.currentDomain.getDefinition("PanoSalado") as Class;			
			layerByName = Dictionary( moduleLoader["layerByName"] );			
			panoSalado = PanoSalado( layerByName["PanoSalado"] );				
			
			this.getSettings();			
			this.buildAll();						
			this.handleStageResize();			
			this.setImage();			
		}		
				
		private function getSettings():void{
			var settings:XML = moduleLoader.xmlByName["HotSpotPlacer"]; 
			this.files = new Array();
			this.files.push( { label:"[default]" } );
			for each(var file:XML in settings.elements()) {
				this.files.push({ label:file }); // urls of files
			}				
			
			settings = moduleLoader.xmlByName["PanoSalado"]; 			
			// gets from settings, after space loaded it can be overwritten by space
			this.cameraFocus = (settings.spaces.@cameraFocus != undefined) ? Number(settings.spaces.@cameraFocus) : 100; 						
			// it can not be overwritten by space, it should though
			this.statistics = (settings.spaces.@statistics != undefined) ? settings.spaces.@statistics == "true" : false; 
		}		
		
		private function buildAll():void {			
			this.cross = new Sprite();
			this.cross.mouseEnabled = false;
			this.cross.mouseChildren = false;
			
			this.hotspotBar = new Sprite();
			this.hotspotBar.graphics.beginFill(0x000000);
			this.hotspotBar.graphics.drawRect(0, 0, 78, 28);
			this.cross.addChild(this.hotspotBar);
			
			this.hotspotAddButton = new Sprite();
			var a_d:Bitmap = new Bitmap(new Bitmap_adddisabled().bitmapData);			
			this.hotspotAddButton.addChild(a_d);
			this.hotspotBar.addChild(this.hotspotAddButton);
			this.hotspotAddButton.x = 3;
			this.hotspotAddButton.y = 3;
			
			this.hotspotRemoveButton = new Sprite();
			var r_d:Bitmap = new Bitmap(new Bitmap_removedisabled().bitmapData);			
			this.hotspotRemoveButton.addChild(r_d);
			this.hotspotBar.addChild(this.hotspotRemoveButton);
			this.hotspotRemoveButton.x = 28;
			this.hotspotRemoveButton.y = 3;
			
			this.hotspotEditButton = new Sprite();
			var e_d:Bitmap = new Bitmap(new Bitmap_editdisabled().bitmapData);			
			this.hotspotEditButton.addChild(e_d);
			this.hotspotBar.addChild(this.hotspotEditButton);
			this.hotspotEditButton.x = 53;
			this.hotspotEditButton.y = 3;			
			
			this.imagefield = new Sprite();
			this.imagefield.name = "imagefield";			
			this.cross.addChild(this.imagefield);			
			this.addChild(this.cross);		
			
			this.txtFormat = new TextFormat();
			this.txtFormat.size = 14;
			this.txtFormat.color = "0xffffff"
			this.txtFormat.blockIndent = 0;
			this.txtFormat.font = "Arial";
			
			this.box = new Sprite();			
			this.box.graphics.beginFill(0x000000);
			this.box.graphics.drawRect(0, 0, 191, 60);
			this.box.graphics.endFill();
			this.addChild(this.box);
			
			this.txtPan = new TextField();	
			this.txtPan.defaultTextFormat = this.txtFormat;
			this.txtPan.height = 18;			
			this.txtPan.width = 100;						
			this.box.addChild(this.txtPan);					
			
			this.txtTilt = new TextField();
			this.txtTilt.defaultTextFormat = this.txtFormat;
			this.txtTilt.y = 18;
			this.txtTilt.height = 18;
			this.txtTilt.width = 100;						
			this.box.addChild(this.txtTilt);			
			
			this.txtZoom = new TextField();
			this.txtZoom.defaultTextFormat = this.txtFormat;
			this.txtZoom.y = 36;
			this.txtZoom.height = 18;
			this.txtZoom.width = 100;						
			this.box.addChild(this.txtZoom);
			
			this.toggleCrossButton = new Sprite();
			var c_i:Bitmap = new Bitmap(new Bitmap_crossvIcon().bitmapData);			
			this.toggleCrossButton.addChild(c_i);
			this.box.addChild(this.toggleCrossButton);
			this.toggleCrossButton.x = 166;
			this.toggleCrossButton.y = 35;
			this.toggleCrossButton.addEventListener(MouseEvent.CLICK, toggleCross);						
			
			this.toggleXmlButton = new Sprite();
			var x_i:Bitmap = new Bitmap(new Bitmap_xmlhIcon().bitmapData);			
			this.toggleXmlButton.addChild(x_i);
			this.box.addChild(this.toggleXmlButton);
			this.toggleXmlButton.x = 140;
			this.toggleXmlButton.y = 35;
			this.toggleXmlButton.addEventListener(MouseEvent.CLICK, toggleXml);			
			
			this.showChangesButton = new Sprite();
			var p_i:Bitmap = new Bitmap(new Bitmap_playIcon().bitmapData);			
			this.showChangesButton.addChild(p_i);
			this.box.addChild(this.showChangesButton);
			this.showChangesButton.x = 114;
			this.showChangesButton.y = 35;
			this.showChangesButton.addEventListener(MouseEvent.CLICK, showchanges);			
						
			this.txtLog = new TextField();
			this.txtLog.text = "###";
			this.txtLog.defaultTextFormat = this.txtFormat;
			this.txtLog.y = 52;
			this.txtLog.height = 18;
			this.txtLog.width = 100;						
			this.box.addChild(this.txtLog);
	
			if(this.files.length>1){			
				this.comboBox = new ComboBox(this.files);
				this.comboBox.y = 65;				
				this.addChild(this.comboBox);
				this.addEventListener(ComboBoxEvent.LABEL_CHANGED, comboBoxLabelChanged);								
			}						
			
			this.configurationWindow = new ConfigurationWindow();			
			this.addChild(this.configurationWindow);			
			//this.configurationWindow.setText(panoSalado.settings);			
		}
		
		
		private function comboBoxLabelChanged(e:ComboBoxEvent):void {
			this.setImage(e.info.label);			
		}		
		
		
		/**
		 * 
		 * @param	e
		 */
		private function spaceLoaded(e:zephyr.BroadcastEvent):void {
			this.currentSpace = e.info.spaceLoaded;
			var spaces:XML= XML(moduleLoader.xmlByName["PanoSalado"].spaces); 
			var space:XML = this.getSpaceById(spaces, this.currentSpace);							
			this.cameraFocus = (space.@cameraFocus != undefined) ? Number(space.@cameraFocus) :			
			((spaces.@cameraFocus != undefined)? Number(spaces.@cameraFocus): 100); // 100 default			
			this.zoom = (space.@cameraZoom != undefined) ? Number(space.@cameraZoom) :			
			((spaces.@cameraZoom != undefined)? Number(spaces.@cameraZoom): 12);	// 12 default										
			this.rescaleImage();			
			this.zoom = 0; // couse initial zoom wont be displayed in txtZoom
			this.getCurrentHotspots();
		}
				
		private var imgLoader:ImageLoader;
		
		private function getCurrentHotspots():void {			
			// get list of SpaceHotspots in current space
			var space:XML = this.getSpaceById(XML((XML(panoSalado.settings)).spaces), this.currentSpace);									
			this.SpaceHotspots = new Array();				
			var imgSrcs:Array = new Array();
			for each(var hotspot:XML in space.elements()) {								
				if (String(hotspot.name()).toLowerCase() == "hotspot") {
					this.SpaceHotspots.push(new Hotspotdata(hotspot.@id, hotspot.@pan, hotspot.@tilt, hotspot.file.text()));					
					imgSrcs.push(hotspot.file.text());
				}				
			}			
			// get size of used SpaceHotspots so it can be detected when center of screen is over hotspot			
			imgLoader = new ImageLoader();
			imgLoader.addEventListener(ImageLoader.LOAD_ERROR,imageLoaderError);		
		    imgLoader.addEventListener(ImageLoader.IMGS_LOADED,imageLoaderDone);		
			imgLoader.loadImgs(imgSrcs);			
		}		
		private function imageLoaderDone(e:Event):void{	
	        imgLoader.removeEventListener(ImageLoader.LOAD_ERROR,imageLoaderDone);
		    imgLoader.removeEventListener(ImageLoader.IMGS_LOADED,imageLoaderError);
			// update SpaceHotspots list with actual sizes
			for (var i:Number = 0; i < imgLoader.bitmapsArray.length; i++ ) {
				(Hotspotdata(this.SpaceHotspots[i])).width = (Bitmap(imgLoader.bitmapsArray[i])).width;
				(Hotspotdata(this.SpaceHotspots[i])).height = (Bitmap(imgLoader.bitmapsArray[i])).height;				
				this.configurationWindow.append((Hotspotdata(this.SpaceHotspots[i])).id);
			}									
			this.imgLoader = null;			
		}	
		private function imageLoaderError(e:Event):void {	
			imgLoader.removeEventListener(ImageLoader.LOAD_ERROR,imageLoaderDone);
		    imgLoader.removeEventListener(ImageLoader.IMGS_LOADED,imageLoaderError);
			// dunno what now -_-'
			// when it fails, how it shows ? is bitmap null or it fails loading rest of them			
		}				
		
		private function toggleCross(e:Event):void {
			this.toggleCrossButton.removeChildAt(0);
			var c_i:Bitmap; 
			if (this.cross.visible) {
				c_i = new Bitmap(new Bitmap_crosshIcon().bitmapData);
				this.cross.visible = false;
				this.comboBox.visible = false;
			}else {
				c_i = new Bitmap(new Bitmap_crossvIcon().bitmapData);
				this.cross.visible = true;
				this.comboBox.visible = true;
			}
			this.toggleCrossButton.addChild(c_i);
		}		
		
		private function toggleXml(e:Event):void {
			this.toggleXmlButton.removeChildAt(0);
			var x_i:Bitmap; 
			if (this.configurationWindow.visible) {
				x_i = new Bitmap(new Bitmap_xmlhIcon().bitmapData);
				this.configurationWindow.visible = false;				
			}else {
				x_i = new Bitmap(new Bitmap_xmlvIcon().bitmapData);
				this.configurationWindow.visible = true;				
			}
			this.toggleXmlButton.addChild(x_i);
		}		
		
		private function showchanges(e:Event):void {
			panoSalado.settings = XML(this.configurationWindow.getText());
			this.configurationWindow.setText(panoSalado.settings);
			panoSalado.loadSpace("reloadSpaces");
		}			
				
		private function centerImageField() :void{
			this.imagefield.x = this.stage.stageWidth * 0.5 - this.imagefield.width * 0.5;
			this.imagefield.y = this.stage.stageHeight * 0.5 - this.imagefield.height * 0.5;
		}
		
		private function handleStageResize(e:Event=null):void {      				
			this.cross.x = this.cross.y = 0;
			var bigCrossWidth:Number = 2;
			this.cross.graphics.clear();
			this.cross.graphics.beginFill(0x000000, 1);
			this.cross.graphics.drawRect(this.stage.stageWidth * 0.5 - bigCrossWidth * 0.5, 0, bigCrossWidth, this.stage.stageHeight)
			this.cross.graphics.drawRect(0, this.stage.stageHeight * 0.5 - bigCrossWidth * 0.5, this.stage.stageWidth, bigCrossWidth);
			this.cross.graphics.endFill();			
			this.centerImageField();			
			this.comboBox.y = 5;
			this.comboBox.x = 200;
			this.box.x = 0
			this.box.y = this.statistics ? 80 : 0;						
			
			this.hotspotBar.x = this.stage.stageWidth - this.hotspotBar.width ;
			this.hotspotBar.y = this.stage.stageHeight *0.5 - this.hotspotBar.height;
		}		
		
		
		private function setImage(label:String = null):void {							
			while(this.imagefield.numChildren>0) {
				this.imagefield.removeChildAt(0);
			}										
			if (label == null || label == "[default]") {				
				var c_i:Bitmap = new Bitmap(new Bitmap_crossIcon().bitmapData);			
				this.imagefield.addChild(c_i);
				this.centerImageField();
			}else {												
				this.hotSpotImage = new Loader();
				var request:URLRequest = new URLRequest(label);
				this.hotSpotImage.load(request);
				this.hotSpotImage.contentLoaderInfo.addEventListener(Event.COMPLETE, imageLoaded);			
				this.hotSpotImage.addEventListener(IOErrorEvent.IO_ERROR, imageNotLoaded);												
			}				
		}
		
		private function imageLoaded(e:Event):void {			
			this.hotSpotImage.removeEventListener(Event.COMPLETE, imageLoaded);
			this.hotSpotImage.removeEventListener(IOErrorEvent.IO_ERROR, imageLoaded);							
			this.imagefield.addChild(this.hotSpotImage);									
			this.centerImageField();
		}			
		
		private function imageNotLoaded(e:Event):void {			
			this.imagefield.removeEventListener(IOErrorEvent.IO_ERROR, imageLoaded);
			this.imagefield.removeEventListener(Event.COMPLETE, imageLoaded);
			TweenLite.killDelayedCallsTo(setImage);
			TweenLite.delayedCall(5, setImage);
		}				
		
		private function updateTxtFields(pan:Number, tilt:Number, zoom:Number):void {
			if (pan  != this.pan)  this.txtPan.text = "pan: " + this.roundToN(this.validatePan(pan),3); 			
			if (tilt != this.tilt) this.txtTilt.text= "tilt: " + -this.roundToN(tilt,3); 						
			if (zoom != this.zoom) this.txtZoom.text= "zoom: " + this.roundToN(zoom,3); 			
		}
		
		private function detectOverHotspot():void {			
			
		}
		
		private function camInit(e:zephyr.BroadcastEvent):void {				
			this.updateTxtFields(e.info.pan, e.info.tilt, e.info.zoom);
			this.pan = e.info.pan;
			this.tilt = e.info.tilt;
			this.zoom = e.info.zoom; 			
		}
		
		private function camSpin(e:zephyr.BroadcastEvent):void {							
			this.updateTxtFields(e.info.spin.split(",")[1], e.info.spin.split(",")[0], this.zoom);				
			if (this.checkHotspots(e.info.spin.split(",")[1], e.info.spin.split(",")[0])) {
				this.txtLog.text = "!- " + overHotspotId;
			}else {
				this.txtLog.text = "nope";
			}
		}
		
		private var overHotspot:Boolean;
		private var overHotspotId:String;
		
		private function checkHotspots(pan:Number, tilt:Number):Boolean {
			for (var i:Number; i < this.SpaceHotspots.length; i++) {
				if ((Hotspotdata(SpaceHotspots[i])).crossInside(pan, tilt)) {
					this.overHotspot = true;
					this.overHotspotId = (Hotspotdata(SpaceHotspots[i])).id;					
					return true;
				}
			}
			this.overHotspot = false;
			return false;
		}		
		
		private function camZoom(e:zephyr.BroadcastEvent):void {							
			this.updateTxtFields(this.pan, this.tilt, e.info.zoom);						
			this.zoom = e.info.zoom; 						
			this.rescaleImage();			
		}
		
		private function rescaleImage():void {
			this.imagefield.scaleX =  this.zoom * (this.cameraFocus/100) / 10;
			this.imagefield.scaleY =  this.zoom * (this.cameraFocus/100) / 10;
			this.centerImageField();
		}
		
		private function roundToN(n:Number,m:Number):Number{
			return Math.round((n*Math.pow(10,m)))/Math.pow(10,m)
		}		
		
		private function validatePan(pan:Number):Number {			 
			return pan - this.roundToN((pan / 360),0)* 360;			
		}		
		
		public function getSpaceById(spaces:XML, id:String):XML{
			for each(var space:XML in spaces.elements()) {			
				if (space.@id == id){ 
					return space; 
				}				
			}
			return null;
		}
	}	
}